<template>
  <a-config-provider
    :locale="zhCN"
    :theme="{
      algorithm: theme.darkAlgorithm,
      token: {
        fontSize: 12,
        borderRadius: 6,
        wireframe: true,
        colorPrimary: '#ff8617',
        colorTextBase: '#fff',
      }
    }"
  >
    <div class="container">
      <search-form class="main-header" :columns="columns" :formData="formData" :formProps="formProps" @search="handleFetchApiDoc" hidden-search-button>
        <template #apiDoc="{ disabled, field, props: fieldProps }">
          <a-input-group compact :style="fieldProps.style">
            <a-input v-model:value="formData[field]" disabled :placeholder="fieldProps.placeholder" :style="fieldProps.inputStyle"></a-input>
            <a-button type="primary" :disabled="disabled" :icon="h(SearchOutlined)" @click="handleShowApiManageModal"></a-button>
          </a-input-group>
        </template>
        <template #actions>
          <a-button type="primary" @click="handleSaveAs">另存为</a-button>
        </template>
      </search-form>
      <div class="main-body">
        <codemirror
          v-model="code"
          class="codemirror"
        />
        <div class="property-panel">
          <a-collapse>
            <a-collapse-panel header="文档信息">
              <custom-form 
                :columns="apiDocColumns" 
                :formData="formData" 
                :formProps="formProps" 
              ></custom-form>
            </a-collapse-panel>
            <a-collapse-panel :header="page.title" v-for="page in pageBingding.pages" :key="page.title">
              <custom-form 
                v-for="methodData in page.apiMethods" 
                :key="methodData.controllerName" 
                :columns="methodColumns" 
                :formData="methodData" 
                :formProps="panelFormProps" 
              ></custom-form>
            </a-collapse-panel>
          </a-collapse>
          <div class="property-footer">
            <a-button class="btn-apply" type="primary" @click="handleApply()">应用接口</a-button>
          </div>
        </div>
      </div>
    
      <ApiManageModal ref="apiManageRef" @select="handleSelectApiDocItem"></ApiManageModal>
    </div>
  </a-config-provider>
</template>

<script lang="ts" setup>
import { SearchOutlined } from '@ant-design/icons-vue';
import { theme } from 'ant-design-vue';
import zhCN from 'ant-design-vue/es/locale/zh_CN';
import { load, OpenApi } from './core/OpenApi';
import { h } from 'vue'
import { useStore } from 'vuex';
import { reactive, ref, watch } from 'vue';
import SearchForm from '@/components/Form/SearchForm.vue'
import ApiManageModal from './components/ApiManageModal.vue';
import { ApplyMethodsParamItem, SinglePageParam, SinglePageVueCodeGeneratorInterface } from './core/VueCodeGenerator';
import { ListQueryPage } from './generators/ListQueryPage';
import { ApiDocItem } from './store/app-types';
import { genPageCodeGenerator } from './utils/batchImportFiles';
import { ListQueryEjsPage } from './generators/EjsListQueryPage';
import { ipcRenderer } from 'electron';

var dynamicGenrators = genPageCodeGenerator()
console.log(dynamicGenrators)

const openapi = ref<OpenApi>(null)
const formProps = reactive<any>({
  'labelCol': { span: 8 },
  'wrapperCol': { span: 16 },
})

const panelFormProps = reactive<any>({
  'labelCol': { span: 4 },
  'wrapperCol': { span: 20 },
})

var generators = {
  ListQueryPage,
  ListQueryEjsPage
}
Object.keys(dynamicGenrators).map((key) => {
  generators[key] = dynamicGenrators[key]
})

const $store = useStore()
const formData: {
  templateName?: string
  controllersDir?: string // 控制器的文件路径
  definitionsDir: string // 实体定义的文件路径
  apiDocUrl? : string // URL
} = reactive($store.state.app.formData)

let pageBingding: {
  title: string
  pages: SinglePageParam[]
} = reactive($store.state.app.pageBingding)
var generator: SinglePageVueCodeGeneratorInterface = new generators[formData.templateName || 'ListQueryPage']()

if(!$store.state.app.pageBingding) {
  $store.dispatch('app/updatePageBinding', {
    title: generator.title,
    pages: generator.pages
  })
}

const apiManageRef = ref(null)

const columns = reactive<any[]>([
  {
    field: 'templateName',
    title: '页面模板',
    type: 'select',
    fieldProps: {
      style: {
        width: '140px'
      },
      options: Object.keys(generators).map((key) => {
        var codeGenerator: SinglePageVueCodeGeneratorInterface = new generators[key]()
        return {
          label: codeGenerator.title,
          value: key,
        }
      })
    }
  },
  {
    field: 'apiDocUrl',
    title: '文档地址',
    slot: 'apiDoc',
    formItemProps: {
      'labelCol': { span: 3 },
      'wrapperCol': { span: 21 },
    },
    fieldProps: {
      style: {
        width: '432px',
      },
      inputStyle: {
        width: '400px',
      },
      placeholder: '请输入文档地址'
    }
  }
])

const apiDocColumns = reactive<any[]>([
  {
    field: 'controllersDir',
    title: '控制器路径',
    fieldProps: {
      placeholder: '请输入控制器路径'
    }
  },
  {
    field: 'definitionsDir',
    title: '实体定义路径',
    fieldProps: {
      placeholder: '请输入实体定义路径'
    }
  }
])


const methodColumns = reactive<any[]>([
  {
    field: 'title',
    title: '接口名称',
    fieldProps: {
      disabled: true,
      style: {
        width: '140px'
      },
    }
  },
  {
    field: 'method',
    title: '绑定接口',
    type: 'select',
    fieldProps: {
      options: [],
      style: {
        width: '240px'
      },
      placeholder: '请选择接口名称',
      showSearch: true,
      filterOption(input: string, option: any) {
        return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0;
      }
    },
    formItemProps: {
      'labelCol': { span: 4 },
      'wrapperCol': { span: 20 },
    }
  }
])

const code = ref<string>()

generator.genCode().then((value) => {
  code.value = value
})

watch(() => formData.templateName, async (key: string) => {
  generator = new generators[key]()
  code.value = await generator.genCode()
  pageBingding.title = generator.title
  pageBingding.pages = generator.pages
})


function handleSelectApiDocItem(item: ApiDocItem) {
  $store.dispatch("app/activeItem", item)
  handleFetchApiDoc(item.url)
}

function handleFetchApiDoc(url: string) {
  load(url).then((api: OpenApi) => {
    openapi.value = api
    methodColumns.forEach((column)=> {
      if(column.field === 'method') {
        column.fieldProps.options = api.controllers.map((ctrl) => {
          return {
            label: ctrl.tag || ctrl.name,
            options: ctrl.methods.map((method) => {
              return {
                label: method.name,
                value: ctrl.name +'.' + method.name
              }
            })
          }
        })

        console.log(column.fieldProps.options)
      }
    })
  })
}

function handleSaveAs() {
  ipcRenderer.send('save-vue-as', code.value)
}

function handleShowApiManageModal() {
  apiManageRef.value.showModal()
}

async function handleApply() {
  
  var items: ApplyMethodsParamItem[] =  pageBingding.pages.map((page) => {
    return page.apiMethods.map((methodData) : ApplyMethodsParamItem => {
      const splits = methodData.method.split('.')
      const controlerName = splits[0]
      const methodName = splits[1]
      const method = openapi.value.findMethod(controlerName, methodName)
      return {
        page: page.title,
        name: methodData.name,
        apiMethod: method,
        controllersDir: formData.controllersDir,
        definitionsDir: formData.definitionsDir
      }
    })
  }).flat()
  generator = new generators[formData.templateName]()
  await generator.applyMethods(openapi.value, items)
  code.value = await generator.genCode()
  $store.dispatch('app/updatePageBinding', {
    title: pageBingding.title,
    pages: pageBingding.pages
  })
}

if(formData.apiDocUrl) {
  handleFetchApiDoc(formData.apiDocUrl)
}

</script>

<style lang="less" scoped>
.container {
  width: 100vw;
  height: 100vh;
  background-color: #181818;
}
.main-header {
  height: 40px;
  border-bottom: 1px solid #282c34;
}

.main-body {
  width: 100vw;
  height: calc(100vh - 80px);
  display: flex;
  display: flex;
  flex-wrap: nowrap;
  justify-content: flex-start;
  align-items: flex-start;

  .codemirror {
    flex: 1;
    width: calc(100vw - 360px);
    height: calc(100vh - 80px);
  }

  .property-panel {
    width: 360px;
    height: calc(100vh - 80px);
    border-left: 1px solid #333;
    background-color: #181818;

    .section-header {
      color: #fff;
      font-size: 12px;
      padding: 16px;
      background-color: #1f1f1f;
    }

    .section-body {
      padding: 16px;
    }

    .property-footer {
      text-align: center;
      margin-top: 30px;
      .btn-apply {
        width: 300px;
      }
    }
  }
}
</style>
